const EventEmitter = require('events').EventEmitter;//(http://nodejs.cn/api/)Node.js文档
const config = require('./config');//（自定义）配置文件

/*自定义房间类*/
/*概念：一个房间对应一个Router管理多个socket连接*/
class MyRoom extends EventEmitter{
    /*房间构造函数*/
    constructor({ roomId,mediaSoupRouter }){
        super();
        this._roomId = roomId;//Room id.
        this._mediaSoupRouter = mediaSoupRouter;// mediaSoup Router instance.
        this._closed = false;// Closed flag.
        this._clientSockets=[];//房间中所有的socket
        this._AppDatas=new Map();//房间中所有的socket对应的自定义数据
    }
    /*创建房间静态方法：初始化Router*/
    static async createRoom({ mediaSoupWorker,roomId }){
        const {mediaSoupSettings:{routerOptions}} = config;//Router配置
        const mediaSoupRouter = await mediaSoupWorker.createRouter(routerOptions);//Worker创建Router
        return new MyRoom({roomId, mediaSoupRouter});
    }
    /*关闭房间*/
    close(){
        this._closed = true;
        this._mediaSoupRouter.close();
        this.emit('close');// Emit 'close' event.
    }
    /*初始化客户端socket*/
    initClientSocket(userName,socket){
        let _this=this;
        const findIndex = this._clientSockets.findIndex(item=>{return item.id==socket.id;});
        if (findIndex>-1){
            /*如果已存在，则需要删除*/
            this._clientSockets[findIndex].disconnect(true);
        }
        /*加入房间*/
        socket.join(_this._roomId);
        /*初始化需要的对象*/
        _this._AppDatas.set(socket.id,{
            userName:userName,//用户名
            device:undefined,//设备信息
            rtpCapabilities:undefined,//客户端rtp配置
            transports:new Map(),//连接
            producers:new Map(),//生产者
            consumers:new Map(),//消费者
        });
        /*处理socket自定义事件*/
        _this.handleSocketRequest(socket);
        /*将要断开连接（但还没有离开rooms）*/
        socket.on('disconnecting', function(reason){
            const index = _this._clientSockets.findIndex(item=>{return item.id==socket.id;});
            if(index>-1){
                _this._clientSockets.splice(index,1);
            }
            _this._AppDatas.get(socket.id).transports.forEach(item=>{
                item.close();
            });
            console.info(`room:${_this._roomId}-${userName}-${socket.id} 断开连接中：${reason}`);
        });
        /*断开连接时触发*/
        socket.on('disconnect', function(reason){
            if(_this._clientSockets.length==0){
                _this.close();
            }
            console.info(`room:${_this._roomId}-${userName}-${socket.id} 已断开连接：${reason}`);
        });
        socket.on('textMessage', function(data) {
            socket.broadcast.emit('onTextMessage',data);
        })
        /*存放所有连接*/
        this._clientSockets.push(socket);
        console.log(this._clientSockets.length)
    }
    /*处理socket请求*/
    handleSocketRequest(socket){
        let _this=this;
        /*获取路由支持的rtp参数，rtpCapabilities具有路由器RTP功能的对象。mediaSoup客户端通常需要这些功能来计算其发送RTP参数*/
        socket.on('getServerRouterRtpCapabilities', (data, callback) => {
            callback(responseSuccess({ routerRtpCapabilities:_this._mediaSoupRouter.rtpCapabilities }));
        });
        /*创建Transport（不区分生产者还是消费者）*/
        socket.on('createServerWebRtcTransport', async (data, callback) => {
            try {
                const { producing,consuming } = data;
                const { transport, transportParams } = await _this.createTransport(producing,consuming);
                _this._AppDatas.get(socket.id).transports.set(transport.id, transport);//保存到socket中
                callback(responseSuccess({ transportParams }));//通知调用成功，并返回参数
            } catch (err) {
                callback(responseError(err));
            }
        });
        /*服务端Transport和客户端Transport连接*/
        socket.on('connectServerWebRtcTransport', async (data, callback) => {
            try {
                const { transportId, dtlsParameters } = data;
                const transport = _this._AppDatas.get(socket.id).transports.get(transportId);
                await transport.connect({ dtlsParameters });
                callback(responseSuccess());//通知调用成功
            } catch (err) {
                callback(responseError(err));
            }
        });
        /*创建服务端生产者Producer,*/
        socket.on('produce', async (data, callback) => {
            try{
                const {transportId,kind,rtpParameters,appData} = data;
                const transport = _this._AppDatas.get(socket.id).transports.get(transportId);
                {
                    const {userName,device} = _this._AppDatas.get(socket.id);
                    appData.socketId=socket.id;
                    appData.userName=userName;
                    appData.device=device;
                }//将socket用户信息存到producer.appData
                const producer = await transport.produce({ kind, rtpParameters,appData });
                _this._AppDatas.get(socket.id).producers.set(producer.id, producer);// Store the Producer
                //顺便需要创建房间中其他客户端对该Producer的消费者Consumer
                for(const clientSocket of _this._clientSockets.filter(item=>{return item.id!=socket.id;})){
                    _this.createConsumer(clientSocket,producer);
                }
                callback(responseSuccess({ producerId: producer.id }));
            }catch (err) {
                callback(responseError(err));
            }
        });
        /*客户端加入房间*/
        socket.on('joinRoom', async (data, callback) => {
            try{
                const {device,rtpCapabilities} = data;
                _this._AppDatas.get(socket.id).device = device;
                _this._AppDatas.get(socket.id).rtpCapabilities = rtpCapabilities;
                let otherClientSockets=_this._clientSockets.filter(item=>{return item.id!=socket.id;})
                for (const clientSocket of otherClientSockets) {
                    //创建其他生产者的消费者
                    for (const producer of _this._AppDatas.get(clientSocket.id).producers.values()) {
                        _this.createConsumer(socket,producer);
                    }
                }
                callback(responseSuccess());
            }catch (err) {
                callback(responseError(err));
            }
        });
        /*关闭生产*/
        socket.on('closeProducer', async (data, callback) => {
            try{
                const {producerId} = data;
                const producer = _this._AppDatas.get(socket.id).producers.get(producerId);
                producer.close();
                _this._AppDatas.get(socket.id).producers.delete(producer.id);
                callback(responseSuccess());
            }catch (err) {
                callback(responseError(err));
            }
        });
        /*暂停生产*/
        socket.on('pauseProducer', async (data, callback) => {
            try{
                const {producerId} = data;
                const producer = _this._AppDatas.get(socket.id).producers.get(producerId);
                await producer.pause();
                console.log(111)
                callback(responseSuccess());
            }catch (err) {
                callback(responseError(err));
            }
        });
        /*恢复生产*/
        socket.on('resumeProducer', async (data, callback) => {
            try{
                const {producerId} = data;
                const producer = _this._AppDatas.get(socket.id).producers.get(producerId);
                await producer.resume();
                console.log(111)
                callback(responseSuccess());
            }catch (err) {
                callback(responseError(err));
            }
        });
    }
    /*创建Transport，可用于媒体流的注入、选择和转发，producing和consuming用来标记是生产还是消费传输*/
    async createTransport(producing,consuming) {
        const { listenIps,maxIncomingBitrate,initialAvailableOutgoingBitrate } = config.mediaSoupSettings.webRtcTransportOptions;
        /*创建一个新的WebRTC传输*/
        const transport = await this._mediaSoupRouter.createWebRtcTransport({ listenIps,initialAvailableOutgoingBitrate,appData:{producing,consuming} });
        if (maxIncomingBitrate) {
            try {
                await transport.setMaxIncomingBitrate(maxIncomingBitrate);//为远程端点通过此传输发送的媒体流设置最大传入比特率
            } catch (error) {
                console.error(error)
            }
        }
        return {
            transport,
            transportParams: {
                id: transport.id,
                iceParameters: transport.iceParameters,
                iceCandidates: transport.iceCandidates,
                dtlsParameters: transport.dtlsParameters,
            }
        };
    }
    /*为consumerSocket创建消费者（producer的消费者）*/
    async createConsumer(consumerSocket, producer) {
        let _this = this;
        const {rtpCapabilities, transports} = _this._AppDatas.get(consumerSocket.id);
        if (!rtpCapabilities || !_this._mediaSoupRouter.canConsume({producerId: producer.id, rtpCapabilities})) {
            return;
        }
        const consumerTransport = Array.from(transports.values()).find((item) => {
            return item.appData.consuming
        });//找到消费者Transport
        let consumer;
        try {
            consumer = await consumerTransport.consume({
                producerId: producer.id,
                rtpCapabilities:rtpCapabilities,
                paused: true
            });// 在暂停模式下创建消费者
            consumer.on('transportclose', () => {
                _this._AppDatas.get(consumerSocket.id).consumers.delete(consumer.id);// Remove from its map.
            });//消费者传输关闭，删除消费者
            consumer.on('producerclose', () =>{
                _this._AppDatas.get(consumerSocket.id).consumers.delete(consumer.id);// Remove from its map.
                consumerSocket.emit('consumerClosed',{ consumerId: consumer.id });
            });//生产者关闭，删除消费者，通知客户端
            consumer.on('producerpause', () => {
                consumerSocket.emit('consumerPaused', { consumerId: consumer.id });
            });//生产者暂停，通知客户端
            consumer.on('producerresume', () => {
                consumerSocket.emit('consumerResumed', { consumerId: consumer.id });
            });//生产者恢复，通知客户端
            consumer.on('trace', (trace) => {
                console.log(`consumer"trace"事件[consumerId:${consumer.id}, trace.type:${trace.type}]`);
            });
        } catch (error) {
            console.log(`创建消费者:${error}`);
            return;
        }
        _this._AppDatas.get(consumerSocket.id).consumers.set(consumer.id, consumer);//保存consumer
        try {
            await socketPromise(consumerSocket,'newConsumer',{
                id             : consumer.id,
                kind           : consumer.kind,
                rtpParameters  : consumer.rtpParameters,
                type           : consumer.type,
                producerPaused : consumer.producerPaused,
                producerId     : producer.id,
                appData        : producer.appData //producer.appData包含socket用户信息
            });//通知客户端创建Consumer
            await consumer.resume();//客户端创建成功之后：开始消费
        }catch (error){
            console.error(`客户端创建失败failed:${error}`);
        }
    }
}

/*给socketio创建返回Promise的一个发射事件方法*/
function socketPromise(socket,eventName, data = {}) {
    return new Promise((resolve,reject) => {
        socket.emit(eventName,data,(res)=>{
            if(res.status==200){
                resolve(res.data);
            } else {
                reject(res.error);
            }
        });//socket.emit(eventName [, ...args][, ack]);//args传参，sck服务端回调函数
    });
};
/*（工具类）socketio响应成功*/
function responseSuccess(data) {
    return {
        status:200,//成功状态
        data
    }
}
/*（工具类）socketio响应失败*/
function responseError(error) {
    return {
        status:1,//失败状态
        error
    }
}

module.exports = MyRoom;
